package dai.core.base

import org.lwjgl.opengl.GL11C
import org.lwjgl.opengl.GL15C
import org.lwjgl.opengl.GL20C
import org.lwjgl.opengl.GL30C.*
import org.lwjgl.system.MemoryUtil
import org.lwjgl.system.MemoryUtil.memFree
import org.w3c.dom.Text


/**
 *
vao ---> | attrib[0] |--- vbo ---> vec3 array { {x,y,z}, ... }; //3d-坐标
|-----------|
| attrib[1] |--- vbo ---> vec2 array { {x,y}, ... }; //whatever
|-----------|
|   ...     |
|-----------|
| attrib[k] |--- vbo ---> vec4 array { {x,y,z,w}, ... };
 *
 */
class Mesh(
    positions: FloatArray,
    texCoords: FloatArray,
    normals:FloatArray,
    indices: IntArray,
    var material: Material,
) {
    val vaoId:Int
    var posVBO: Int
    var texCoordVBO: Int
    var normalVBO: Int
    var indicesVBO:Int
    var vertexCount: Int = indices.size
    init {
        // vao
        vaoId = glGenVertexArrays()
        glBindVertexArray(vaoId)

        // position vbo
        val vertexBuffer = MemoryUtil.memAllocFloat(positions.size)
        vertexBuffer.put(positions).flip()
        posVBO = glGenBuffers()
        glBindBuffer(GL_ARRAY_BUFFER, posVBO)
        glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW)
        glEnableVertexAttribArray(0)
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0)
        memFree(vertexBuffer)

        // texture coords vbo
        val texCoordBuffer = MemoryUtil.memAllocFloat(texCoords.size)
        texCoordBuffer.put(texCoords).flip()
        texCoordVBO = glGenBuffers()
        glBindBuffer(GL_ARRAY_BUFFER,texCoordVBO)
        glBufferData(GL_ARRAY_BUFFER,texCoordBuffer, GL_STATIC_DRAW)
        glEnableVertexAttribArray(1)
        glVertexAttribPointer(1,2, GL_FLOAT,false,0,0)
        memFree(texCoordBuffer)

        // normal vbo
        val normalBuffer = MemoryUtil.memAllocFloat(normals.size)
        normalBuffer.put(normals).flip()
        normalVBO = glGenBuffers()
        glBindBuffer(GL_ARRAY_BUFFER,normalVBO)
        glBufferData(GL_ARRAY_BUFFER,normalBuffer, GL_STATIC_DRAW)
        glEnableVertexAttribArray(2)
        glVertexAttribPointer(2,3, GL_FLOAT,false,0,0)
        memFree(normalBuffer)

        // ibo
        val indicesBuffer = MemoryUtil.memAllocInt(indices.size)
        indicesBuffer.put(indices).flip()
        indicesVBO = glGenBuffers()
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesVBO)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW)
        memFree(indicesBuffer)

        // unbind
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        glBindVertexArray(0)
    }

    fun cleanup() {
        glDisableVertexAttribArray(0)
        glDisableVertexAttribArray(1)
        glDisableVertexAttribArray(2)

        // delete vbo
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        glDeleteBuffers(posVBO)
        glDeleteBuffers(texCoordVBO)
        glDeleteBuffers(normalVBO)

        // delete vao
        glBindVertexArray(0)
        glDeleteVertexArrays(vaoId)

        material?.let { it.texture?.let { texture ->
            glDeleteTextures(texture.texId)
        } }
    }

    fun render(block:()->Unit = {}) {
        material?.let {
            it.texture?.let { texture ->
                glActiveTexture(GL_TEXTURE0)
                glBindTexture(GL_TEXTURE_2D,texture.texId)
            }
        }
        block.invoke()
        glBindVertexArray(vaoId)
        glDrawElements(GL_TRIANGLES, vertexCount, GL_UNSIGNED_INT, 0)
        glBindVertexArray(0)
    }
}